LuxSum 2 软件体系结构 BMS

LuxSum 2 软件体系结构 BMS

cover

软件体系结构实验项目,要求完成基于体系风格 Main program and subroutine 的图书查询管理系统,花了不到一周时间完成,系统后端基于python的flask框架,前端基于flask自带的模板引擎jinjia2实现,并使用wcgi http服务器gunicorn结合nginx反向代理部署于vps中:

BookManagementSystem

关于Main program and subroutine

Introduction

Main program and subroutine被认为是 Hierarchical Architecture的一个分支,也被认为是Call-and-Return Systems中的一类。该风格依据自上而下的 层次结构将系统划分为主程序和子程序,主程序和子程序充当Components,调研返回机制充当Connectors,调用关系具有层次性,其语义逻辑表现为子程序的正确性,取决于它调用的子程序的正确性。

Features

Modularized

使用自上而下的层次结构将系统细化为不同子模块,从而实现模块重用子模块的自由开发。系统细化/模块化的过程必须符合couplingcohesion的标准。

The aim of this style is to reuse the modules and freely develop individual modules or subroutine. In this style, a software system is divided into subroutines by using top-down refinement according to desired functionality of the system.

These refinements lead vertically until the decomposed modules is simple enough to have its exclusive independent responsibility. Functionality may be reused and shared by multiple callers in the upper layers.

Procedures are grouped into modules following such criteria as coupling and cohesion.

For languages without support for modularization this often results in a system organized around a main program and a set of subroutines.

Order & Time & Call-and-Return

这种风格是系统函数式分解的自然结果,其分解后的顶层模块作为控制模块/主程序,其主要任务是以正确的顺序分时性地调用其他模块。因此控制模块通常为单线程。

In the main program with subroutines architectural style, the main tasks of the system, are allocated to different components, which are called, in the appropriate order, from a control component. The decomposition is strongly geared towards an ordering of the various actions to be performed with respect to time. The top-level component controls this ordering.

The system can be described as a hierarchy of procedure definitions. This style is a natural outcome of a functional decomposition of a system. The top level module acts as the main program. Its main task is to invoke the other modules in the correct order. As a consequence, there is usually a single thread of control.

The main program acts as the driver for the subroutines, typically providing a control loop for sequencing through the
subroutines in some order.

在经过自上而下地层次性划分后,最上层控制模块调用下层模块。这种层次性有严格和非严格两种,表现为能否完成模块的跨层调用。

Procedures and modules are defined in a hierarchy. Higher level modules call lower-level modules. The hierarchy may be strict, in which case modules at level n can only call modules at level n-1, or it may be weak, in which case modules at level n may call modules at level n-i, with i≥1.

Characteristic

Advantages

  • Easy to decompose the system based on hierarchy refinement.
  • Can be used in a subsystem of object oriented design.

Disadvantages

  • Vulnerable as it contains globally shared data.
  • Tight coupling may cause more ripple effects of changes.

系统主体设计

Database Design

Datebase

这里使用了简单轻便的关系型数据库SQLite3,使用它的原因主要是:

  • SQLite3轻便简单,占用资源低,运行速度快;
  • python自带,配置简单;
  • mysql早已删除🤣

ORM

还是选择了SQLAlchemy,之前在写app后端时早已使用熟练。其类似于Java里的Hibernate,将Java中的Javabean和xml文件整合在了一起。同时具有全面的查询语法。

ER Graph

ER

管理员未做数据表,因此管理员登录实际是假登录(配置文件设置了一个管理员账号);

每个数据表的具体信息不赘述,详见github中model.pymk_database.py

Back-end Design

Basic

后端方面没什么可说的,都是些无趣的重复工作,view.py里面随便写了几个基本函数,大致实现登陆注册和增删改查这些功能。大致有两个feature:

  • 做了两个搜索,一个单条件查询的相关性搜索,书籍和词条的相关性与查询词条的连续子串在书籍信息中的出现次数和该子串的长度成正比;以及一个多条件高级查询,必须词条和数据库中内容严格匹配才能查询到结果。
  • 一些可能的重复代码都被提取作为单独的函数/子程序被重复调用,以尽可能地满足要求风格。

With main program and subroutine

如何在该系统后端中体现出main program and subroutine的体系风格?

Python instead of Java

Procedure Oriented

考虑到该体系风格是一种相当简单的非常函数式的风格,常被用于面向过程的无模块、对象设计的语言中,因此我使用Python语言而非Java语言来编写。因为尽管这两种语言都是面向对象的,但python并未像java那样强制性的要求使用面向对象的写法,且python包含了对函数式编程的支持,这使得在python上编写出符合main program and subroutine风格的代码成为可能。

Single Thread

main program and subroutine要求控制模块一般使用单线程执行,但由于本系统基于python的flask框架编写,其实质的控制模块位于服务器上的gunicorn这个wcgi http server中,难以对其线程情况进行要求。但是使用C语言写的python解释器中存在全局解释器锁(GIL锁),这导致python解释器在同一时间只能运行一个线程的代码,变相导致位于gunicorn中的控制模块使用实际意义上的单线程执行。

Flask instead of J2EE

不同于J2EE的难以体现出子程序思想的Servlet/JSP式写法,flask的工作原理本身便是main program and subroutine风格的一种体现:

利用werkzeug(服务器上为gunicorn)作为WCGI服务器,其接收浏览器的http请求并在解包后调用flask的app函数,并在其内部根据url路由转发到具体的子函数当中,这个子函数/子程序完成对post/get请求的处理后,调用jinjia2模板引擎包装的html文件,返回给浏览器相应的数据和页面。

这里的werkzeug/gunicorn作为逻辑控制者,充当着这里的控制模块,按http请求按顺序分时性的不断调用app函数中的各个路由处理子函数,这里的app可以作为次级子模块也可作为虚拟的模块(将view.py文件中的各个路由子函数作为次级子模块),路由子函数要么执行相应的处理,要么执行可复用(提取出来的)子函数们。

Front-end Design

Basic

前端使用flask自带的jinjia2这样一种模板引擎,其具有模板继承功能,可以先编写template式的base.html文件,再在各个独立的文件中extend该文件,对每个模块进行重写以完成独立的功能。此外,jinjia2具有控制逻辑,可以完成一些基本的业务逻辑。

html&css方面同样使用了Bootstrap框架,由于对css3并不十分了解,只能直接套用bootstrap的template/snippet。在显示表格时,直接使用的bootstrap-table插件,其根据预置url请求数据,并具有非常完善的功能。消息提示方面和以前一样使用了Toastr插件,在每个html页面内加入一个响应固定值的函数,并在加载时调用,即可在加载完成时显示通知。

在前端的设计方面主要秉持三个思路:

  • 简单直接:由于是图书管理查询系统,查询/搜索作为最主要的功能被放在index界面最中央的位置,让用户一目了然,并暗示用户进行搜索操作,从而借阅书籍;
  • 减少加载:登录注册等功能都从子页面简化为了模态框,可以在当前页面加载并进行操作,让用户在相同的点击次数下提前看到相应的界面,减少了加载时间。
  • 先多后少:主界面为单条件的相关性搜索框,让用户首先进行模糊搜索,进入搜索结果页面后,显示高级/多条件搜索的入口,让用户根据当前结果的多少来决定是否进入高级的严格搜索筛选结果。符合用户思考习惯。

With main program and subroutine

如何在该系统前端中体现出main program and subroutine的体系风格?

Model Frame instead of Sub Pages

模态框本质是使用JavaScript调用预置窗口控件。在前端的页面中,较多的使用了模态框替代子页面,这固然可以让用户更加快捷直观看见目标窗口,而实际上体现的也是一种main program and subroutine的思想:用户作为主程序,逻辑性的控制点击按钮,JavaScript的函数作为子程序响应调用相应的模态窗口。此外,在JavaScript的子程序中,还存在对其他JavaScript函数/子程序的调用,这样形成了一种层次性的拓扑结构,点击显示这种相应作为调用返回机制,充当连接件,充分体现了main program and subroutine的风格。

Q&A

Q1:对CSS/Bootstrap栅格系统不熟悉,难以布置表格界面

仔细阅读了bootstrap的文档,对其有了基本的了解,并通过不断地试错后完成了html的编写;

表格显示部分,由于对表格功能有一定要求,而直接写表格难以完成这些要求,因此使用了bootstrap-table插件,根据预置url请求数据,从而向数据库获取信息,从而完善了表格功能。

Q2:Jinjia2作为一种年轻而文档少的模板引擎,容易因为疏忽出现bug,且难以完成调试

增加组员review机制:在阶段性地编写完成一段代码后并完成基本测试后,即时push到github上,让组员进行review。这样通过review机制可以减少bug的出现,在bug出现通过多人debug的方式也可以有效提高效率。此外,组员review可以通过其他人审视代码风格,进一步确认代码是符合要求风格的。

Q3: 如何体现要求风格?

查阅了相当多的中英文资料后发现大多数资料都是大同小异,有效信息很少,可参考的代码也没有什么参考性,这让我认识到这种风格本身便非常简单普适且具有“可解释性”,不用刻意去体现这种风格,因为本来常用的代码编写、程序运行便存在该种风格的影子。

Q4: 如何完成相关性搜索?

在系统设计之前我浏览了各大高校的图书馆网站,发现它们的一大共同点在于可以根据简略的词条按相关性显示搜索结果,在排除智能算法后,我根据词条本身的特征暴力计算其和书籍信息的匹配程度,尽管算法的复杂度不低,但在这样一个简单的系统中仍可快速运行。

总结

这个项目是软件体系结构的一个小实验,主要要求按照给定的体系风格来写一个相应的系统。隔了很久,来写这个总结。之前偶有灵光,想总结的系统一些,但拖的太久,只能零碎地写几点:

  • 该忘的东西都忘了,对于这个项目的主要记忆大概只有那个被jinjia2折磨的下午和看组员答辩时那个极度失望的早晨。

  • 学习的主要目的大概就是不断地差异化与同质化吧,通过不断地区分,最终周围都是和自己水平差不多的人,并且随着学历的越高,这种差异就会越小。希望以后能够不要再碰见令我失望的组员了,这也要靠我自己努力才行啊。

  • 项目做的再认真,一次糟糕的答辩都能轻而易举地摧毁它,这大概就是这门课程给我带来的主要启示。

来源